import { RouteConfig } from 'vue-router'
import { VuexModule, Module, Mutation, Action, getModule } from 'vuex-module-decorators'
import { getLocale } from '@/lang'
import { TagView, ErrorLog, App } from '@TG/interface/types/app'
import { SubsystemConfig } from '@TG/interface/types/subsystem'
import router, { resetRouter } from '@TG/kit/router'
import { getAppSidebarStatus, setAppSidebarStatus, setAppLanguage, getAppComponentSize, setAppComponentSize } from '@TG/kit/cookie'
import store from '@TG/store'

@Module({ dynamic: true, store, name: 'appModule' })
class AppModule extends VuexModule implements App {
  public pageSize = {
    width: document.documentElement.clientWidth,
    height: document.documentElement.clientHeight
  }
  public sidebar = {
    opened: getAppSidebarStatus() !== 'closed',
    withoutAnimation: false
  }
  public language = getLocale()
  public componentSize = getAppComponentSize()
  public typerInitialized: boolean = false;
  public accessedSubsystems: SubsystemConfig[] = []
  public accessedRoutes: RouteConfig[] = []
  public currentSubsystem: SubsystemConfig = { id: '', name: '' }
  public currentRoute: RouteConfig = { path: '/' }
  public visitedTagViews: TagView[] = []
  public cachedViews: string[] = []
  public errorlogs: ErrorLog[] = []

  @Mutation
  private SET_PAGE_SIZE(pageSize: { width: number, height: number }) {
    this.pageSize = pageSize
  }

  @Mutation
  private TOGGLE_SIDEBAR(withoutAnimation: boolean) {
    this.sidebar.opened = !this.sidebar.opened
    this.sidebar.withoutAnimation = withoutAnimation
    if (this.sidebar.opened) {
      setAppSidebarStatus('opend')
    } else {
      setAppSidebarStatus('closed')
    }
  }

  @Mutation
  private SET_LANGUAGE(language: string) {
    this.language = language
    setAppLanguage(this.language)
  }

  @Mutation
  private SET_COMPONENT_SIZE(componentSize: string) {
    this.componentSize = componentSize
    setAppComponentSize(this.componentSize)
  }

  @Mutation
  private SET_TYPER_INITIALIZED(typerInitialized: boolean) {
    this.typerInitialized = typerInitialized
  }

  @Mutation
  private SET_ACCESSED_SUBSYSTEMS(accessedSubsystems: SubsystemConfig[]) {
    this.accessedSubsystems = accessedSubsystems
  }

  @Mutation
  private SET_ACCESSED_ROUTES(accessedRoutes: RouteConfig[]) {
    this.accessedRoutes = accessedRoutes
    // 将路由添加到路由器
    resetRouter()
    router.addRoutes(accessedRoutes)
  }

  @Mutation
  private SET_CURRENT_SUBSYSTEM(currentSubsystem: SubsystemConfig) {
    this.currentSubsystem = currentSubsystem
  }

  @Mutation
  private SET_CURRENT_ROUTE(currentRoute: RouteConfig) {
    this.currentRoute = currentRoute
  }

  @Mutation
  private SET_VISITED_TAG_VIEWS(visitedTagViews: TagView[]) {
    this.visitedTagViews = visitedTagViews
  }

  @Mutation
  private ADD_VISITED_TAG_VIEW(tagView: TagView) {
    if (this.visitedTagViews.some(visitedTagView => visitedTagView.path === tagView.path)) {
      return
    }
    this.visitedTagViews.push(
      Object.assign({}, tagView, {
        title: tagView.meta.title || 'no-name'
      })
    )
  }

  @Mutation
  private ADD_CACHED_VIEW(tagView: TagView) {
    const name = tagView.name
    if (this.cachedViews.includes(name)) {
      return
    }
    if (!tagView.meta.noCache) {
      this.cachedViews.push(name)
    }
  }

  @Mutation
  private DEL_VISITED_TAG_VIEW(tagView: TagView) {
    for (const [i, visitedTagView] of this.visitedTagViews.entries()) {
      if (visitedTagView.path === tagView.path) {
        this.visitedTagViews.splice(i, 1)
        break
      }
    }
  }

  @Mutation
  private DEL_CACHED_VIEW(tagView: TagView) {
    const index = this.cachedViews.indexOf(tagView.name)
    index > -1 && this.cachedViews.splice(index, 1)
  }

  @Mutation
  private DEL_OTHERS_VISITED_TAG_VIEWS(tagView: TagView) {
    this.visitedTagViews = this.visitedTagViews.filter(visitedTagView => {
      return visitedTagView.meta.affix || visitedTagView.path === tagView.path
    })
  }

  @Mutation
  private DEL_OTHERS_CACHED_VIEWS(tagView: TagView) {
    const index = this.cachedViews.indexOf(tagView.name)
    if (index > -1) {
      this.cachedViews = this.cachedViews.slice(index, index + 1)
    } else {
      // if index = -1, there is no cached tags
      this.cachedViews = []
    }
  }

  @Mutation
  private DEL_ALL_VISITED_TAG_VIEWS() {
    // keep affix tags
    const affixTags = this.visitedTagViews.filter(visitedTagView => visitedTagView.meta.affix)
    this.visitedTagViews = affixTags
  }

  @Mutation
  private DEL_ALL_CACHED_VIEWS() {
    this.cachedViews = []
  }

  @Mutation
  private UPDATE_VISITED_TAG_VIEW(tagView: TagView) {
    for (let visitedTagView of this.visitedTagViews) {
      if (visitedTagView.path === tagView.path) {
        visitedTagView = Object.assign(visitedTagView, tagView)
        break
      }
    }
  }

  @Mutation
  private ADD_ERROR_LOG(errorLog: ErrorLog) {
    this.errorlogs.push(errorLog)
  }

  @Mutation
  private CLEAR_ERROR_LOG() {
    this.errorlogs = []
  }

  @Mutation
  private CLEAR() {
    this.accessedSubsystems = []
    this.accessedRoutes = []
    this.currentSubsystem = { id: '', name: '' }
    this.currentRoute = { path: '' }
    this.visitedTagViews = []
    this.cachedViews = []
  }

  @Action
  public setPageSize(pageSize: { width: number, height: number }) {
    this.SET_PAGE_SIZE(pageSize)
  }

  @Action
  public toggleSidebar(withoutAnimation: boolean) {
    this.TOGGLE_SIDEBAR(withoutAnimation)
  }

  @Action
  public setLanguage(language: string) {
    this.SET_LANGUAGE(language)
  }

  @Action
  public setComponentSize(componentSize: string) {
    this.SET_COMPONENT_SIZE(componentSize)
  }

  @Action
  public setTyperInitialized(typerInitialized: boolean) {
    this.SET_TYPER_INITIALIZED(typerInitialized)
  }

  @Action
  public setAccessedSubsystems(accessedSubsystems: SubsystemConfig[]) {
    this.SET_ACCESSED_SUBSYSTEMS(accessedSubsystems)
  }

  @Action
  public setAccessedRoutes(accessedRoutes: RouteConfig[]) {
    this.SET_ACCESSED_ROUTES(accessedRoutes)
  }

  @Action
  public setCurrentSubsystem(currentSubsystem: SubsystemConfig) {
    this.SET_CURRENT_SUBSYSTEM(currentSubsystem)
  }

  @Action
  public setCurrentRoute(currentRoute: RouteConfig) {
    this.SET_CURRENT_ROUTE(currentRoute)
  }

  @Action
  public setVisitedTagViews(visitedTagViews: TagView[]) {
    this.SET_VISITED_TAG_VIEWS(visitedTagViews)
  }

  @Action
  public addVisitedTagView(tagView: TagView) {
    this.ADD_VISITED_TAG_VIEW(tagView)
  }

  @Action
  public addCachedView(tagView: TagView) {
    this.ADD_CACHED_VIEW(tagView)
  }

  @Action
  public addView(tagView: TagView) {
    this.ADD_VISITED_TAG_VIEW(tagView)
    this.ADD_CACHED_VIEW(tagView)
  }

  @Action
  public delVisitedTagView(tagView: TagView) {
    this.DEL_VISITED_TAG_VIEW(tagView)
  }

  @Action
  public delCachedView(tagView: TagView) {
    this.DEL_CACHED_VIEW(tagView)
  }

  @Action
  public delView(tagView: TagView) {
    this.DEL_VISITED_TAG_VIEW(tagView)
    this.DEL_CACHED_VIEW(tagView)
  }

  @Action
  public delOthersVisitedTagView(tagView: TagView) {
    this.DEL_OTHERS_VISITED_TAG_VIEWS(tagView)
  }

  @Action
  public delOthersCachedViews(tagView: TagView) {
    this.DEL_OTHERS_CACHED_VIEWS(tagView)
  }

  @Action
  public delOthersViews(tagView: TagView) {
    this.DEL_OTHERS_VISITED_TAG_VIEWS(tagView)
    this.DEL_OTHERS_CACHED_VIEWS(tagView)
  }

  @Action
  public delAllVisitedTagView() {
    this.DEL_ALL_VISITED_TAG_VIEWS()
  }

  @Action
  public delAllCachedViews() {
    this.DEL_ALL_CACHED_VIEWS()
  }

  @Action
  public delAllViews() {
    this.DEL_ALL_VISITED_TAG_VIEWS()
    this.DEL_ALL_CACHED_VIEWS()
  }

  @Action
  public updateVisitedTagView(tagView: TagView) {
    this.UPDATE_VISITED_TAG_VIEW(tagView)
  }

  @Action
  public addErrorLog(errorLog: ErrorLog) {
    this.ADD_ERROR_LOG(errorLog)
  }

  @Action
  public clearErrorLog() {
    this.CLEAR_ERROR_LOG()
  }

  @Action
  public clear() {
    this.CLEAR()
    this.CLEAR_ERROR_LOG()
    resetRouter()
  }
}

export const appModule = getModule(AppModule)
